mirror of https://github.com/mpv-player/mpv
filter_kernels: Keep f.radius in terms of dest/filter coords.
The existing code modifies f.radius so that it is in terms of the filter sample radius (in the source coordinate space) and has some small errors because of this behavior. This commit changes f.radius so that it is always in terms of the filter function radius (in the destination coordinate space). The sample radius can always be derived by multiplying f.radius by filter_scale, which is the new, more descriptive name for the previous inv_scale.
This commit is contained in:
parent
69cc9f2a2c
commit
e226041355
|
@ -28,6 +28,7 @@
|
|||
#include <assert.h>
|
||||
|
||||
#include "filter_kernels.h"
|
||||
#include "common/common.h"
|
||||
|
||||
// NOTE: all filters are designed for discrete convolution
|
||||
|
||||
|
@ -60,19 +61,20 @@ bool mp_init_filter(struct filter_kernel *filter, const int *sizes,
|
|||
{
|
||||
assert(filter->f.radius > 0);
|
||||
// Only downscaling requires widening the filter
|
||||
filter->inv_scale = inv_scale >= 1.0 ? inv_scale : 1.0;
|
||||
filter->f.radius *= filter->inv_scale;
|
||||
filter->filter_scale = MPMAX(1.0, inv_scale);
|
||||
double src_radius = filter->f.radius * filter->filter_scale;
|
||||
// Polar filters are dependent solely on the radius
|
||||
if (filter->polar) {
|
||||
filter->size = 1;
|
||||
filter->size = 1; // Not meaningful for EWA/polar scalers.
|
||||
// Safety precaution to avoid generating a gigantic shader
|
||||
if (filter->f.radius > 16.0) {
|
||||
filter->f.radius = 16.0;
|
||||
if (src_radius > 16.0) {
|
||||
src_radius = 16.0;
|
||||
filter->filter_scale = src_radius / filter->f.radius;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
int size = ceil(2.0 * filter->f.radius);
|
||||
int size = ceil(2.0 * src_radius);
|
||||
// round up to smallest available size that's still large enough
|
||||
if (size < sizes[0])
|
||||
size = sizes[0];
|
||||
|
@ -87,7 +89,7 @@ bool mp_init_filter(struct filter_kernel *filter, const int *sizes,
|
|||
// largest filter available. This is incorrect, but better than refusing
|
||||
// to do anything.
|
||||
filter->size = cursize[-1];
|
||||
filter->inv_scale *= (filter->size/2.0) / filter->f.radius;
|
||||
filter->filter_scale = (filter->size/2.0) / filter->f.radius;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +117,7 @@ static double sample_filter(struct filter_kernel *filter, double x)
|
|||
{
|
||||
// The window is always stretched to the entire kernel
|
||||
double w = sample_window(&filter->w, x / filter->f.radius * filter->w.radius);
|
||||
double k = sample_window(&filter->f, x / filter->inv_scale);
|
||||
double k = sample_window(&filter->f, x);
|
||||
return filter->clamp ? fmax(0.0, fmin(1.0, w * k)) : w * k;
|
||||
}
|
||||
|
||||
|
@ -130,7 +132,7 @@ static void mp_compute_weights(struct filter_kernel *filter, double f,
|
|||
double sum = 0;
|
||||
for (int n = 0; n < filter->size; n++) {
|
||||
double x = f - (n - filter->size / 2 + 1);
|
||||
double w = sample_filter(filter, x);
|
||||
double w = sample_filter(filter, x / filter->filter_scale);
|
||||
out_w[n] = w;
|
||||
sum += w;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,10 @@ struct filter_kernel {
|
|||
bool polar; // whether or not the filter uses polar coordinates
|
||||
// The following values are set by mp_init_filter() at runtime.
|
||||
int size; // number of coefficients (may depend on radius)
|
||||
double inv_scale; // scale factor (<1.0 is upscale, >1.0 downscale)
|
||||
double filter_scale; // Factor to convert the mathematical filter
|
||||
// function radius to the possibly wider
|
||||
// (in the case of downsampling) filter sample
|
||||
// radius.
|
||||
};
|
||||
|
||||
extern const struct filter_window mp_filter_windows[];
|
||||
|
|
|
@ -3400,6 +3400,9 @@ void gl_video_configure_queue(struct gl_video *p, struct vo *vo)
|
|||
const struct filter_kernel *kernel =
|
||||
mp_find_filter_kernel(p->opts.scaler[SCALER_TSCALE].kernel.name);
|
||||
if (kernel) {
|
||||
// filter_scale wouldn't be correctly initialized were we to use it here.
|
||||
// This is fine since we're always upsampling, but beware if downsampling
|
||||
// is added!
|
||||
double radius = kernel->f.radius;
|
||||
radius = radius > 0 ? radius : p->opts.scaler[SCALER_TSCALE].radius;
|
||||
queue_size += 1 + ceil(radius);
|
||||
|
|
|
@ -107,8 +107,8 @@ void pass_sample_separated_gen(struct gl_shader_cache *sc, struct scaler *scaler
|
|||
|
||||
void pass_sample_polar(struct gl_shader_cache *sc, struct scaler *scaler)
|
||||
{
|
||||
double radius = scaler->kernel->f.radius;
|
||||
int bound = (int)ceil(radius);
|
||||
double radius = scaler->kernel->f.radius * scaler->kernel->filter_scale;
|
||||
int bound = ceil(radius);
|
||||
bool use_ar = scaler->conf.antiring > 0;
|
||||
GLSL(color = vec4(0.0);)
|
||||
GLSLF("{\n");
|
||||
|
|
Loading…
Reference in New Issue