X-Git-Url: https://git.sesse.net/?p=movit;a=blobdiff_plain;f=resample_effect.cpp;h=802a8968a893482460988b910f2db707d68b692b;hp=1f6c47c9d236a56ec688ff52d21452083600fc95;hb=f8e5ddc082f2267198292ea9e53d4a8b45f7b3b1;hpb=3306a4a0d2300767eeef71ab877fdf1587d13475 diff --git a/resample_effect.cpp b/resample_effect.cpp index 1f6c47c..802a896 100644 --- a/resample_effect.cpp +++ b/resample_effect.cpp @@ -435,8 +435,8 @@ bool ResampleEffect::set_float(const string &key, float value) { SingleResamplePassEffect::SingleResamplePassEffect(ResampleEffect *parent) : parent(parent), direction(HORIZONTAL), - input_width(1280), - input_height(720), + input_width(1280), + input_height(720), offset(0.0), zoom(1.0), last_input_width(-1), @@ -502,7 +502,7 @@ void SingleResamplePassEffect::update_texture(GLuint glsl_program_num, const str assert(false); } - ScalingWeights weights = calculate_scaling_weights(src_size, dst_size, zoom, offset); + ScalingWeights weights = calculate_bilinear_scaling_weights(src_size, dst_size, zoom, offset); src_bilinear_samples = weights.src_bilinear_samples; num_loops = weights.num_loops; slice_height = 1.0f / weights.num_loops; @@ -529,6 +529,8 @@ void SingleResamplePassEffect::update_texture(GLuint glsl_program_num, const str tex.update(weights.src_bilinear_samples, weights.dst_samples, internal_format, GL_RG, type, pixels); } +namespace { + ScalingWeights calculate_scaling_weights(unsigned src_size, unsigned dst_size, float zoom, float offset) { // Only needed if run from outside ResampleEffect. @@ -605,15 +607,16 @@ ScalingWeights calculate_scaling_weights(unsigned src_size, unsigned dst_size, f // to compute the destination pixel, and how many depend on the scaling factor. // Thus, the kernel width will vary with how much we scale. float radius_scaling_factor = min(scaling_factor, 1.0f); - int int_radius = lrintf(LANCZOS_RADIUS / radius_scaling_factor); - int src_samples = int_radius * 2 + 1; + const int int_radius = lrintf(LANCZOS_RADIUS / radius_scaling_factor); + const int src_samples = int_radius * 2 + 1; unique_ptr[]> weights(new Tap[dst_samples * src_samples]); float subpixel_offset = offset - lrintf(offset); // The part not covered by whole_pixel_offset. assert(subpixel_offset >= -0.5f && subpixel_offset <= 0.5f); + float inv_scaling_factor = 1.0f / scaling_factor; for (unsigned y = 0; y < dst_samples; ++y) { // Find the point around which we want to sample the source image, // compensating for differing pixel centers as the scale changes. - float center_src_y = (y + 0.5f) / scaling_factor - 0.5f; + float center_src_y = (y + 0.5f) * inv_scaling_factor - 0.5f; int base_src_y = lrintf(center_src_y); // Now sample pixels on each side around that point. @@ -626,16 +629,33 @@ ScalingWeights calculate_scaling_weights(unsigned src_size, unsigned dst_size, f } } + ScalingWeights ret; + ret.src_bilinear_samples = src_samples; + ret.dst_samples = dst_samples; + ret.num_loops = num_loops; + ret.bilinear_weights_fp16 = nullptr; + ret.bilinear_weights_fp32 = move(weights); + return ret; +} + +} // namespace + +ScalingWeights calculate_bilinear_scaling_weights(unsigned src_size, unsigned dst_size, float zoom, float offset) +{ + ScalingWeights ret = calculate_scaling_weights(src_size, dst_size, zoom, offset); + unique_ptr[]> weights = move(ret.bilinear_weights_fp32); + const int src_samples = ret.src_bilinear_samples; + // Now make use of the bilinear filtering in the GPU to reduce the number of samples // we need to make. Try fp16 first; if it's not accurate enough, we go to fp32. // Our tolerance level for total error is a bit higher than the one for invididual // samples, since one would assume overall errors in the shape don't matter as much. const float max_error = 2.0f / (255.0f * 255.0f); unique_ptr[]> bilinear_weights_fp16; - int src_bilinear_samples = combine_many_samples(weights.get(), src_size, src_samples, dst_samples, &bilinear_weights_fp16); + int src_bilinear_samples = combine_many_samples(weights.get(), src_size, src_samples, ret.dst_samples, &bilinear_weights_fp16); unique_ptr[]> bilinear_weights_fp32 = nullptr; double max_sum_sq_error_fp16 = 0.0; - for (unsigned y = 0; y < dst_samples; ++y) { + for (unsigned y = 0; y < ret.dst_samples; ++y) { double sum_sq_error_fp16 = compute_sum_sq_error( weights.get() + y * src_samples, src_samples, bilinear_weights_fp16.get() + y * src_bilinear_samples, src_bilinear_samples, @@ -648,13 +668,10 @@ ScalingWeights calculate_scaling_weights(unsigned src_size, unsigned dst_size, f if (max_sum_sq_error_fp16 > max_error) { bilinear_weights_fp16.reset(); - src_bilinear_samples = combine_many_samples(weights.get(), src_size, src_samples, dst_samples, &bilinear_weights_fp32); + src_bilinear_samples = combine_many_samples(weights.get(), src_size, src_samples, ret.dst_samples, &bilinear_weights_fp32); } - ScalingWeights ret; ret.src_bilinear_samples = src_bilinear_samples; - ret.dst_samples = dst_samples; - ret.num_loops = num_loops; ret.bilinear_weights_fp16 = move(bilinear_weights_fp16); ret.bilinear_weights_fp32 = move(bilinear_weights_fp32); return ret;